package common

import (
	"context"
	"github.com/coreos/etcd/clientv3"
	"log"
	"strings"
	"time"
)

type Etcd struct {
	Client  *clientv3.Client
	Kv      clientv3.KV
	Lease   clientv3.Lease
	Watcher clientv3.Watcher
}

var (
	GEtcd *Etcd
)

func InitEtcd() (err error) {
	var (
		config clientv3.Config
	)
	GEtcd = &Etcd{}
	config = clientv3.Config{
		Endpoints:   GConfig.Viper.GetStringSlice("EtcdEndpoints"),
		DialTimeout: time.Duration(GConfig.Viper.GetInt("EtcdDialTimeout")) * time.Millisecond,
	}
	if GEtcd.Client, err = clientv3.New(config); err != nil {
		log.Println(err.Error())
		return
	}

	GEtcd.Kv = clientv3.NewKV(GEtcd.Client)
	GEtcd.Lease = clientv3.NewLease(GEtcd.Client)
	GEtcd.Watcher = clientv3.NewWatcher(GEtcd.Client)
	return err
}

//保存job
func (et *Etcd) JobSave(jobByte []byte) (oldJob *Job, err error) {
	var (
		job    *Job
		putRes *clientv3.PutResponse
	)
	job = &Job{}

	if job, err = UnPackJob(jobByte); err != nil {
		return
	}

	if putRes, err = et.Kv.Put(context.TODO(), ETCD_JOBS_DIR+job.Name, string(jobByte), clientv3.WithPrevKV()); err != nil {
		return
	}
	if putRes.PrevKv != nil {
		if oldJob, err = UnPackJob(putRes.PrevKv.Value); err != nil {
			return
		}
	}

	return
}

//获取joblist
func (et *Etcd) JobList() (joblist []*Job, err error) {
	var (
		getRes *clientv3.GetResponse
		job    *Job
	)
	if getRes, err = et.Kv.Get(context.TODO(), ETCD_JOBS_DIR, clientv3.WithPrefix()); err != nil {
		return
	}
	joblist = make([]*Job, 0)
	for _, v := range getRes.Kvs {
		if job, err = UnPackJob(v.Value); err != nil {
			log.Println(err)
			continue
		}
		joblist = append(joblist, job)
	}
	return
}

//删除job
func (et *Etcd) JobDel(jobByte []byte) (oldJob *Job, err error) {
	var (
		job    *Job
		delRes *clientv3.DeleteResponse
	)

	if job, err = UnPackJob(jobByte); err != nil {
		return
	}
	if delRes, err = et.Kv.Delete(context.TODO(), ETCD_JOBS_DIR+job.Name, clientv3.WithPrevKV()); err != nil {
		return
	}
	if len(delRes.PrevKvs) == 1 {
		if oldJob, err = UnPackJob(delRes.PrevKvs[0].Value); err != nil {
			log.Println(err)
		}
		return
	}

	return
}

//kill job
func (et *Etcd) JobKill(jobByte []byte) (err error) {
	var (
		job      *Job
		leaseRes *clientv3.LeaseGrantResponse
	)

	if job, err = UnPackJob(jobByte); err != nil {
		return
	}

	if leaseRes, err = et.Lease.Grant(context.TODO(), 1); err != nil {
		return
	}

	if _, err = et.Kv.Put(context.TODO(), ETCD_KILL_DIR+job.Name, "", clientv3.WithLease(leaseRes.ID)); err != nil {
		return
	}

	return
}

//worker list
func (et *Etcd) WorkList() (list []string, err error) {
	var (
		getRes *clientv3.GetResponse
	)

	if getRes, err = et.Kv.Get(context.TODO(), ETCD_WORKER_DIR, clientv3.WithPrefix()); err != nil {
		return
	}
	list = make([]string, 0)
	for _, v := range getRes.Kvs {
		list = append(list, strings.TrimLeft(string(v.Key), ETCD_WORKER_DIR))
	}
	log.Printf("%+v",list)

	return
}


